#include "asm_utils.h"
#include "interrupt.h"
#include "stdio.h"
#include "program.h"
#include "thread.h"
#include "sync.h"

// 屏幕IO处理器
STDIO stdio;
// 中断管理器
InterruptManager interruptManager;
// 程序管理器
ProgramManager programManager;

Semaphore except_tabacco,except_paper,except_match,finish;

typedef enum{
    EXCEPT_TABACCO=0,
    EXCEPT_PAPER,
    EXCEPT_MATCH,
}Ingredient;


void agent(void *arg)
{
    int delay = 0;
    static int rand = 7;//初始化一个值,伪装成随机数
    printf("agent: start to randomly generate 2 ingredients\n");

    while(1){
        int ingred = rand%3;
        // 使用线性同余法更新 rand
        rand = (1664525 * rand + 1013904223) % 0x80000000;
        switch (ingred)
        {
        case EXCEPT_TABACCO:
            except_tabacco.V();
            printf("agent: generate paper and match\n");
            break;
        
        case EXCEPT_PAPER:
            except_paper.V();
            printf("agent: generate tabacco and match\n");
            break;

        case EXCEPT_MATCH:
            except_match.V();
            printf("agent: generate paper and tabacco\n");
            break;
        
        default:
            break;
        }
        printf("agent: waiting for smoker finish...\n");
        finish.P();
    }
}

void smoker_with_tabacco(void *arg)
{
    while(1){
        // get ingredients
        printf("smoker_with_tabacco  : waiting for paper and match...\n");
        except_tabacco.P();
        printf("smoker_with_tabacco  : Got paper and match!\n");
        //smoke for a while
        printf("smoker_with_tabacco: smoking......\n");
        int delay = 0xfffffff;
        while(delay--);
        //finish
        finish.V();
        printf("smoker_with_tabacco: I am finished\n");
    }
}

void smoker_with_paper(void *arg)
{
    while(1){
        // get ingredients
        printf("smoker_with_paper  : waiting for tabacco and match....\n");
        except_paper.P();
        printf("smoker_with_paper   : Got tabacco and match!\n");
        //smoke for a while
        printf("smoker_with_paper: smoking......\n");
        int delay = 0xfffffff;
        while(delay--);
        //finish
        finish.V();
        printf("smoker_with_paper: I am finished!\n");

    }
}

void smoker_with_match(void *arg)
{
    while(1){
        // get ingredients
        printf("smoker_with_match  : waiting for paper and tabacco...\n");
        except_match.P();
        printf("smoker_with_match   : Got paper and tabacco!\n");
        //smoke for a while
        printf("smoker_with_match: smoking......\n");
        int delay = 0xfffffff;
        while(delay--);
        //finish
        finish.V();
        printf("smoker_with_match: I am finished\n");
    }
}


void first_thread(void *arg)
{
    // 第1个线程不可以返回
    stdio.moveCursor(0);
    for (int i = 0; i < 25 * 80; ++i)
    {
        stdio.print(' ');
    }
    stdio.moveCursor(0);

    except_tabacco.initialize(0);
    except_paper.initialize(0);
    except_match.initialize(0);
    finish.initialize(0);

    programManager.executeThread(agent, nullptr, "second thread", 1);
    programManager.executeThread(smoker_with_tabacco, nullptr, "third thread", 1);
    programManager.executeThread(smoker_with_paper, nullptr, "forth thread", 1);
    programManager.executeThread(smoker_with_match, nullptr, "fifth thread", 1);

    asm_halt();
}

extern "C" void setup_kernel()
{

    // 中断管理器
    interruptManager.initialize();
    interruptManager.enableTimeInterrupt();
    interruptManager.setTimeInterrupt((void *)asm_time_interrupt_handler);

    // 输出管理器
    stdio.initialize();

    // 进程/线程管理器
    programManager.initialize();

    // 创建第一个线程
    int pid = programManager.executeThread(first_thread, nullptr, "first thread", 1);
    if (pid == -1)
    {
        printf("can not execute thread\n");
        asm_halt();
    }

    ListItem *item = programManager.readyPrograms.front();
    PCB *firstThread = ListItem2PCB(item, tagInGeneralList);
    firstThread->status = RUNNING;
    programManager.readyPrograms.pop_front();
    programManager.running = firstThread;
    asm_switch_thread(0, firstThread);

    asm_halt();
}
